package com.cl.websocketboot.inteceptors;

import com.cl.websocketboot.constant.Constant;
import com.cl.websocketboot.entity.UserInfo;
import com.cl.websocketboot.handler.ApplicationContextHandler;
import com.cl.websocketboot.utils.JsonUtil;
import com.cl.websocketboot.utils.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
public class MessageStatusInterceptor implements ChannelInterceptor {

    private SimpMessagingTemplate getSimpMessagingTemplate() {
        return ApplicationContextHandler.getBean(SimpMessagingTemplate.class);
    }

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        // 可以通过 StompHeaderAccessor来获取用户的状态 (登录、退出、发送信息)
        final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        if (accessor == null) {
            log.error("获取用户 状态 失败");
            return message;
        }
        String roomId;
        Set<String> users;
        if (StompCommand.CONNECT == accessor.getCommand()) {
            final String username = accessor.getFirstNativeHeader("username");
            roomId = accessor.getFirstNativeHeader("roomId");

            users = Constant.usersInRoom.get(roomId);
            if (null == users) {  //如果users为空，表示该用户是第一个进到房间的
                users = new HashSet<>();
                users.add(username);
                Constant.usersInRoom.put(roomId, users);
            } else { //房间中有人
                users.add(username);
            }

            String channelId = accessor.getSessionId();  //获取同道的id
            UserInfo userInfo = new UserInfo(username, roomId);

            Constant.channelId2UserInfo.put(channelId, userInfo);
            log.info("加入聊天:{},当前用户数：{}", userInfo, Constant.getUserNum());
            pushUsers(roomId, users);
            String messageJson = Constant.systemMessageJson(roomId, username + " 加入了聊天。");
            getSimpMessagingTemplate().convertAndSend("/room/" + roomId + "/message", messageJson);
            return message;
        }

        //连接的断开
        if (StompCommand.DISCONNECT == accessor.getCommand()) {
            String channelId = accessor.getSessionId();  //获取同道的id

            UserInfo userInfo = Constant.channelId2UserInfo.get(channelId);
            if (userInfo == null) {
                log.error("channelId:{},数据不存在", channelId);
                return message;
            }
            roomId = userInfo.getRoomId();
            String username = userInfo.getUsername();

//             1.将用户从房间移除掉
//             2.给房间中的所有的人发信息
            users = Constant.usersInRoom.get(roomId); //获取房间内所有的用户
            users.remove(username);
            log.info("退出聊天:{},当前用户数：{}", userInfo, Constant.getUserNum());
            pushUsers(roomId, users);
            String messageJson = Constant.systemMessageJson(roomId, username + " 退出了聊天。");
            getSimpMessagingTemplate().convertAndSend("/room/" + roomId + "/message", messageJson);
            return message;
        }
        return message;
    }

    private void pushUsers(String roomId, Set<String> users) {
        String usersJson = JsonUtil.toString(users);
        if (ObjectUtils.isEmpty(usersJson)) {
            log.error("房间{}无用户", roomId);
            usersJson = "[]";
        }
        getSimpMessagingTemplate().convertAndSend("/room/" + roomId, usersJson);
    }

    @SuppressWarnings("unchecked")
    public static <T> T cast(Object obj) {
        try {
            return (T) obj;
        } catch (ClassCastException e) {
            log.error("类强转失败:{}", obj, e);
            return null;
        }
    }


}
